#ifndef CONFIG_MANAGER_H
#define CONFIG_MANAGER_H

#include <iostream>
#include <fstream>
#include <map>
#include <vector>
#include <functional>
#include <mutex>
#include "nlohmann/json.hpp"
#include "base_callback_list.h"

namespace El {
namespace Common {

class ConfigManager {

    ConfigManager();
    ~ConfigManager();

public:
    static ConfigManager &GetInstance();

    bool LoadConfig(const std::string &filename, const std::string &defaultConfigFilename);

    nlohmann::json GetConfig(const std::string &key);
    bool SetConfig(const std::string &key, const nlohmann::json &value);

    nlohmann::json GetDefaultConfig(const std::string &key);
    bool SetDefaultConfig(const std::string &key, const nlohmann::json &value);

    int32_t Register(const std::string &key, std::function<bool(const nlohmann::json &)> listener);
    void Unregister(const std::string &key, int32_t listenerId);

    int32_t RegisterVerify(const std::string &key, std::function<bool(const nlohmann::json &)> listener);
    void UnregisterVerify(const std::string &key, int32_t listenerId);

private:
    bool NotifyListeners(const std::string &key, const nlohmann::json &value);
    bool LoadConfigFromFile(const std::string &filename);
    bool SaveConfig(const std::string &filename);
    bool SaveConfigToFile(const std::string &filename);
    void BackupConfig(const std::string &filename);
    bool LoadDefaultConfig(const std::string &defaultConfigFilename);
    void MergeConfigs(const nlohmann::json &defaultConfig);
    bool SaveDefaultConfig(const std::string &filename);

private:
    nlohmann::json defaultConfig_;
    std::mutex mutex_;
    nlohmann::json config_;
    std::map<std::string, Base::CallbackList<bool, const nlohmann::json &>> listeners_;
    std::map<std::string, Base::CallbackList<bool, const nlohmann::json &>> listenersVerify_;
    std::string filename_;
    std::string defaultFilename_;
};

} // namespace Common
} // namespace El

#endif // CONFIG_MANAGER_H
